package logger

import (
	"os"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

// 设置日志编码器
func GetEnCoder() zapcore.Encoder {
	config := zap.NewProductionEncoderConfig()
	//设置日志中时间的格式
	config.EncodeTime = zapcore.ISO8601TimeEncoder
	//设置日志中级别的格式
	config.EncodeLevel = zapcore.CapitalLevelEncoder
	//序列化时间到纳秒
	// config.EncodeDuration = zapcore.NanosDurationEncoder
	//路径显示段路径，也就是相对路径
	config.EncodeCaller = zapcore.ShortCallerEncoder
	//按原样序列化记录器名称
	config.EncodeName = zapcore.FullNameEncoder
	return zapcore.NewConsoleEncoder(config)
}

// 生成普通信息的Writer
func GetInfoWriterSyncer(dir string) zapcore.WriteSyncer {
	//引入第三方库 Lumberjack 加入日志切割功能
	infoLumberIO := &lumberjack.Logger{
		Filename:   dir + "/info.log",
		MaxSize:    10, // megabytes
		MaxBackups: 100,
		MaxAge:     28,    // days
		Compress:   false, //Compress确定是否应该使用gzip压缩已旋转的日志文件。默认值是不执行压缩。
	}
	return zapcore.AddSync(infoLumberIO)
}

// 生成故障信息的Writer
func GetErrorWriterSyncer(dir string) zapcore.WriteSyncer {
	//引入第三方库 Lumberjack 加入日志切割功能
	lumberWriteSyncer := &lumberjack.Logger{
		Filename:   dir + "/error.log",
		MaxSize:    10, // 单位M
		MaxBackups: 100,
		MaxAge:     28,    // 天数
		Compress:   false, //Compress确定是否应该使用gzip压缩已旋转的日志文件。默认值是不执行压缩。
	}
	return zapcore.AddSync(lumberWriteSyncer)
}

type Level int8

const (
	DEBUG Level = iota
	INFO
	WARN
	ERROR
	FATAL
	PANIC
)

var LevelMap = map[Level]string{
	DEBUG: "DEBUG",
	INFO:  "INFO",
	WARN:  "WARN",
	ERROR: "ERROR",
	FATAL: "FATAL",
	PANIC: "PANIC",
}

func (s Level) String() string {
	v, ok := LevelMap[s]
	if ok {
		return `"` + v + `"`
	}
	return ""
}

type Log struct {
	level    Level
	saveFile bool
	dirPath  string
	logger   *zap.SugaredLogger
}

func NewDefaultLog() *Log {
	return &Log{
		level:    DEBUG,
		saveFile: false,
	}
}
func NewSaveFileLog(path string) *Log {
	return &Log{
		level:    DEBUG,
		saveFile: true,
		dirPath:  path,
	}
}

func (g *Log) GetLogger() {
	//如果level写错，则表示为info
	level := map[Level]zapcore.Level{
		DEBUG: zapcore.DebugLevel,
		INFO:  zapcore.InfoLevel,
		WARN:  zapcore.WarnLevel,
		ERROR: zapcore.ErrorLevel,
		FATAL: zapcore.FatalLevel,
		PANIC: zapcore.PanicLevel,
	}
	if g.dirPath == "" {
		g.dirPath = "."
	}
	encoder := GetEnCoder()
	//输出普通日志
	infowriter := GetInfoWriterSyncer(g.dirPath)
	//输出异常日志
	errwriter := GetErrorWriterSyncer(g.dirPath)
	//确定日志级别
	infolevel := zap.LevelEnablerFunc(func(l zapcore.Level) bool {
		if zap.InfoLevel >= level[g.level] {
			return l < zap.ErrorLevel && l >= level[g.level]
		}
		return l < zap.ErrorLevel && l >= zap.DebugLevel
	})
	errlevel := zap.LevelEnablerFunc(func(l zapcore.Level) bool {
		if level[g.level] >= zap.ErrorLevel {
			return l >= level[g.level]
		}
		return l >= zap.ErrorLevel
	})
	infocore := zapcore.NewCore(encoder, infowriter, infolevel)
	errcore := zapcore.NewCore(encoder, errwriter, errlevel)
	consolecore := zapcore.NewCore(encoder, zapcore.AddSync(os.Stdout), level[g.level])
	var logger *zap.Logger
	if g.saveFile {
		var core []zapcore.Core
		if level[g.level] >= zap.ErrorLevel {
			core = []zapcore.Core{errcore, consolecore}
		} else {
			core = []zapcore.Core{infocore, errcore, consolecore}
		}
		logger = zap.New(zapcore.NewTee(core...), zap.AddCaller())
	} else {
		logger = zap.New(consolecore, zap.AddCaller())
	}
	g.logger = logger.Sugar()
}

// 获取一个日志
func (g *Log) L() *zap.SugaredLogger {
	if g.logger == nil {
		g.GetLogger()
	}
	return g.logger
}

func (g *Log) SetLevel(level Level) {
	if level <= DEBUG {
		g.level = DEBUG
	} else if level >= PANIC {
		g.level = PANIC
	} else {
		g.level = level
	}
	g.GetLogger()
}

func (g *Log) SetSaveFile(save bool) {
	g.saveFile = save
}

func (g *Log) SetDirPath(path string) bool {
	if g.saveFile {
		g.dirPath = path
		return true
	}
	return false
}
